package com.shelpe.services.sinbad.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import com.shelpe.services.sinbad.controller.sinbad.User2Controller.UserMobileDto;
import com.shelpe.services.sinbad.dto.UserViewDto;
import com.shelpe.services.sinbad.entity.jpa.Campaign;
import com.shelpe.services.sinbad.entity.jpa.DriveType;
import com.shelpe.services.sinbad.entity.jpa.OnlineStatus;
import com.shelpe.services.sinbad.entity.jpa.PurchaseOrder;
import com.shelpe.services.sinbad.entity.jpa.Tactics;
import com.shelpe.services.sinbad.entity.jpa.User;
import com.shelpe.services.sinbad.entity.jpa.UserInfo;
import com.shelpe.services.sinbad.repository.jpa.CampaignRepository;
import com.shelpe.services.sinbad.repository.jpa.PurchaseOrderRepository;
import com.shelpe.services.sinbad.repository.jpa.TacticsRepository;
import com.shelpe.services.sinbad.repository.jpa.UserInfoRepository;
import com.shelpe.services.sinbad.repository.jpa.UserRepository;
import com.shelpe.services.sinbad.utils.DateUtil;

import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class UserSmsService {
	public static final String MOBILE_PATTERN = "^((13[0-9])|(15[^4])|(18[0,2,3,5-9])|(17[0-8])|(147))\\d{8}$";

	@Autowired
	private UserInfoRepository userInfoRepository;
	@Autowired
	private UserRepository userRepository;
	@Autowired
	private PurchaseOrderRepository purchaseOrderRepository;
	@Autowired
	private CampaignRepository campaignRepository;
	@Autowired
	private TacticsRepository tacticsRepository;

	public UserMobileDto findBySmsUser(String type) {
		UserMobileDto retDto = new UserMobileDto();
		retDto.setAll(new ArrayList<UserViewDto>());
		retDto.setUse(new ArrayList<UserViewDto>());
		retDto.setNouse(new ArrayList<UserViewDto>());
		retDto.setPause(new ArrayList<UserViewDto>());
		// List<UserViewDto> retDto = new ArrayList<UserViewDto>();
		// 订购的所有用户
		List<User> users = this.userRepository.findAll(new Specification<User>() {
			@Override
			public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				Predicate p = cb.equal(root.get("userType"), 1);
				p = cb.and(p, cb.greaterThan(root.get("purchaseTime"), new Date()));
				p = cb.and(p, cb.equal(root.get("established"), 1));
				query.where(p);
				List<Order> orders = new ArrayList<Order>();
				orders.add(cb.desc(root.get("createdTime")));
				query.orderBy(orders);
				return query.getRestriction();
			}
		});
		Map<String, User> userMap = new HashMap<String, User>();
		for (User user : users) {
			userMap.put(user.getNick(), user);
		}

		// 填写了信息的用户
		List<UserInfo> userInfos = (List<UserInfo>) this.userInfoRepository.findAll();
		Map<Long, UserInfo> userInfoMap = new HashMap<Long, UserInfo>();
		for (UserInfo info : userInfos) {
			userInfoMap.put(info.getUserID(), info);
		}

		List<User> needUsers = new ArrayList<User>();
		if (users != null && users.size() > 0) {
			for (User user : users) {
				if (userInfoMap.get(user.getUserID()) != null) {
					if (userInfoMap.get(user.getUserID()).getTel().matches(MOBILE_PATTERN)) {
						needUsers.add(user);
					}
				}
			}
		}
		List<String> nicks = new ArrayList<String>();
		if (needUsers != null && needUsers.size() > 0) {
			for (User user : users) {
				nicks.add(user.getNick());
			}
		}

		// 根据订单来确定最准确的时间
		List<PurchaseOrder> maxOrders = null;
		List<PurchaseOrder> minOrders = null;
		if (nicks != null && nicks.size() > 0) {
			maxOrders = this.purchaseOrderRepository.findNickByPurchaseTime(nicks);
			minOrders = this.purchaseOrderRepository.findNickByMinPurchaseTime(nicks);
		}

		Map<String, PurchaseOrder> maxOrderMap = new HashMap<String, PurchaseOrder>();
		for (PurchaseOrder order : maxOrders) {
			maxOrderMap.put(order.getNick(), order);
		}

		// 获取到满足类型的用户
		List<PurchaseOrder> needOrders = new ArrayList<PurchaseOrder>();
		for (PurchaseOrder minOrder : minOrders) {
			PurchaseOrder maxOrder = maxOrderMap.get(minOrder.getNick());
			if (maxOrder != null) {
				// fourth,fifth,index2serven,index2three,index2one
				Date today = DateUtil.parseDate2date(DateFormatUtils.format(new Date(), "yyyy-MM-dd"));
				if ("fourth".equals(type)) {
					if (DateUtil.convertBetweenDay(minOrder.getOrderCycleStart(), today) == 4L) {
						needOrders.add(minOrder);
					}
				} else if ("fifth".equals(type)) {
					if (DateUtil.convertBetweenDay(minOrder.getOrderCycleStart(), today) == 15L && DateUtil
							.convertBetweenDay(minOrder.getOrderCycleStart(), maxOrder.getOrderCycleEnd()) != 15) {
						needOrders.add(minOrder);
						continue;
					}
				} else if ("index2serven".equals(type)) {
					if (DateUtil.convertBetweenDay(today, maxOrder.getOrderCycleEnd()) == 7L) {
						needOrders.add(minOrder);
						continue;
					}

				} else if ("index2three".equals(type)) {
					if (DateUtil.convertBetweenDay(today, maxOrder.getOrderCycleEnd()) == 3L) {
						needOrders.add(minOrder);
						continue;
					}
				} else if ("index2one".equals(type)) {
					if (DateUtil.convertBetweenDay(today, maxOrder.getOrderCycleEnd()) == 0L) {
						needOrders.add(minOrder);
						continue;
					}
				}
			}
		}

		// 获取到满足功能的用户
		List<Long> userIDs = new ArrayList<Long>();// 获取满足类型的用户
		for (PurchaseOrder order : needOrders) {
			User user = userMap.get(order.getNick());
			if (user != null) {
				userIDs.add(user.getUserID());
			}
		}
		log.debug("find {} num userIDs:{}", userIDs.size(), userIDs);
		// 获取所有用户时,直接返回
		if (userIDs != null && userIDs.size() > 0) {
			for (long userID : userIDs) {
				UserViewDto dto = new UserViewDto();
				UserInfo info = userInfoMap.get(userID);
				if (info != null) {
					dto.setUserID(userID);
					dto.setMobile(NumberUtils.toLong(info.getTel()));
					retDto.getAll().add(dto);
				}
			}
		}

		List<Long> needUserIDs = new ArrayList<Long>();// 获取要发送短信的用户
		List<Long> needUseUserIDs = new ArrayList<Long>();// 使用中的
		List<Long> needPauseUserIDs = new ArrayList<Long>();// 暂停的

		// 低价引流|规则||无线|重力
		List<Campaign> campaigns = this.campaignRepository.findByUserIDIn(userIDs);
		Map<Long, List<Campaign>> campaignMap = new HashMap<Long, List<Campaign>>();
		List<Long> campaignUsrIDs = new ArrayList<Long>();// 计划级别查到的用户id
		if (campaigns != null && campaigns.size() > 0) {
			for (Campaign campaign : campaigns) {
				if (campaignUsrIDs.indexOf(campaign.getUserID()) == -1) {
					campaignUsrIDs.add(campaign.getUserID());
				}
				List<Campaign> campaignofusers = campaignMap.get(campaign.getUserID());
				if (campaignofusers == null) {
					campaignofusers = new ArrayList<Campaign>();
					campaignMap.put(campaign.getUserID(), campaignofusers);
				}
				campaignofusers.add(campaign);
			}
		}
		for (Map.Entry<Long, List<Campaign>> entry : campaignMap.entrySet()) {
			for (Campaign campaign : entry.getValue()) {
				if (campaign.getAutoType() != DriveType.manual && campaign.getOnlineStatus() == OnlineStatus.online) {
					needUserIDs.add(entry.getKey());
					needUseUserIDs.add(entry.getKey());
					break;
				} else if (campaign.getAutoType() != DriveType.manual
						&& campaign.getOnlineStatus() == OnlineStatus.offline) {
					needUserIDs.add(entry.getKey());
					needPauseUserIDs.add(entry.getKey());
					break;
				}
			}
		}

		userIDs.removeAll(campaignUsrIDs);// 在计划级别判断过的userID过滤掉
		// 卡位
		List<Tactics> rankings = this.tacticsRepository.findByUserIDIn(userIDs);
		List<Long> rankingOfUserIDs = new ArrayList<Long>();
		Map<Long, List<Tactics>> rankingMap = new HashMap<Long, List<Tactics>>();
		if (rankings != null && rankings.size() > 0) {
			for (Tactics ranking : rankings) {
				if (rankingOfUserIDs.indexOf(ranking.getUserID()) == -1) {
					rankingOfUserIDs.add(ranking.getUserID());
				}
				List<Tactics> rankingofusers = rankingMap.get(ranking.getUserID());
				if (rankingofusers == null) {
					rankingofusers = new ArrayList<Tactics>();
					rankingMap.put(ranking.getUserID(), rankingofusers);
				}
				rankingofusers.add(ranking);
			}
		}
		for (Map.Entry<Long, List<Tactics>> entry : rankingMap.entrySet()) {
			for (Tactics ranking : entry.getValue()) {
				if (ranking.getStatus() == Tactics.Status.starting || ranking.getStatus() == Tactics.Status.finish) {// use
					needUserIDs.add(entry.getKey());
					needUseUserIDs.add(entry.getKey());
					break;
				}
				if (ranking.getStatus() == Tactics.Status.pause) {// pause
					needUserIDs.add(entry.getKey());
					needPauseUserIDs.add(entry.getKey());
					break;
				}
			}
		}
		// 一键加词?

		log.debug("find {} num userIDs:{}", needUserIDs.size(), needUserIDs);
		userIDs.removeAll(needUserIDs);
		if (userIDs != null && userIDs.size() > 0) {
			for (long userID : userIDs) {
				UserViewDto dto = new UserViewDto();
				UserInfo info = userInfoMap.get(userID);
				if (info != null) {
					dto.setUserID(userID);
					dto.setMobile(NumberUtils.toLong(info.getTel()));
					retDto.getNouse().add(dto);
				}
			}
		}

		if (needPauseUserIDs != null && needPauseUserIDs.size() > 0) {// pause
			for (long userID : needPauseUserIDs) {
				UserViewDto dto = new UserViewDto();
				UserInfo info = userInfoMap.get(userID);
				if (info != null) {
					dto.setUserID(userID);
					dto.setMobile(NumberUtils.toLong(info.getTel()));
					retDto.getPause().add(dto);
				}
			}
		}

		if (needUseUserIDs != null && needUseUserIDs.size() > 0) {// use
			for (long userID : needUseUserIDs) {
				UserViewDto dto = new UserViewDto();
				UserInfo info = userInfoMap.get(userID);
				if (info != null) {
					dto.setUserID(userID);
					dto.setMobile(NumberUtils.toLong(info.getTel()));
					retDto.getUse().add(dto);
				}
			}
		}

		return retDto;
	}
}
